{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import glob\n",
    "\n",
    "\n",
    "task_results = glob.glob(\"/home/gautier/Desktop/plancraft/outputs/2024-02-15/22-32-07/*/*.json\")\n",
    "goal_histories = glob.glob(\"/home/gautier/Desktop/plancraft/outputs/2024-02-15/22-32-07/*/*.jsonl\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import json\n",
    "from collections import defaultdict\n",
    "\n",
    "task_data = {}\n",
    "for task_result in task_results:\n",
    "    with open(task_result, \"r\") as f:\n",
    "        n = task_result.split(\"/\")[-2]\n",
    "        task_data[n] = json.load(f)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "obtain_wooden_slab\n",
      "26\n",
      "{'success_count': 26, 'success_rate': 0.8666666666666667, 'num_evals': 30, 'episode_lengths': [1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 2999, 1962, 1962, 1962, 1962, 2999, 1962, 612, 1362, 1962, 1962, 1962, 1962, 1962]}\n",
      "obtain_planks\n",
      "24\n",
      "{'success_count': 24, 'success_rate': 0.8, 'num_evals': 30, 'episode_lengths': [1962, 2999, 514, 353, 1962, 349, 1962, 1962, 1147, 1962, 532, 1962, 311, 1158, 1962, 1962, 576, 1205, 1962, 1962, 1951, 1962, 2414, 983]}\n",
      "obtain_wooden_button\n",
      "23\n",
      "{'success_count': 23, 'success_rate': 0.7666666666666667, 'num_evals': 30, 'episode_lengths': [1962, 1212, 2999, 762, 1962, 2999, 1962, 996, 1962, 632, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962]}\n",
      "obtain_sign\n",
      "27\n",
      "{'success_count': 27, 'success_rate': 0.9, 'num_evals': 30, 'episode_lengths': [1962, 1962, 2362, 762, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1562, 1962, 1962, 2580, 1812, 1962, 1962, 1962]}\n",
      "obtain_wooden_pressure_plate\n",
      "26\n",
      "{'success_count': 26, 'success_rate': 0.8666666666666667, 'num_evals': 30, 'episode_lengths': [1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1862, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 2911, 1962, 1376, 1962, 1962, 1962, 1962, 1962]}\n",
      "obtain_chest\n",
      "24\n",
      "{'success_count': 24, 'success_rate': 0.8, 'num_evals': 30, 'episode_lengths': [2999, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 612, 1962, 1962, 1962, 1812, 1962, 2999, 1962, 1962, 1962, 2152, 2999, 1962, 1962, 1962, 2297]}\n",
      "obtain_stick\n",
      "26\n",
      "{'success_count': 26, 'success_rate': 0.8666666666666667, 'num_evals': 30, 'episode_lengths': [1962, 1962, 616, 2012, 1962, 1962, 1962, 323, 1962, 1962, 1962, 1962, 1083, 1962, 1962, 1962, 1962, 388, 1962, 1962, 1662, 612, 1212, 1962, 1962, 1962]}\n",
      "obtain_oak_stairs\n",
      "26\n",
      "{'success_count': 26, 'success_rate': 0.8666666666666667, 'num_evals': 30, 'episode_lengths': [1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962]}\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/tmp/ipykernel_12706/812973444.py:1: DeprecationWarning: \n",
      "Pyarrow will become a required dependency of pandas in the next major release of pandas (pandas 3.0),\n",
      "(to allow more performant data types, such as the Arrow string type, and better interoperability with other libraries)\n",
      "but was not found to be installed on your system.\n",
      "If this would cause problems for you,\n",
      "please provide us feedback at https://github.com/pandas-dev/pandas/issues/54466\n",
      "        \n",
      "  import pandas as pd\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>task</th>\n",
       "      <th>success_count</th>\n",
       "      <th>num_evals</th>\n",
       "      <th>success_rate</th>\n",
       "      <th>average_episode_length</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>obtain_wooden_slab</td>\n",
       "      <td>26</td>\n",
       "      <td>30</td>\n",
       "      <td>0.866667</td>\n",
       "      <td>1966.769231</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>obtain_planks</td>\n",
       "      <td>24</td>\n",
       "      <td>30</td>\n",
       "      <td>0.800000</td>\n",
       "      <td>1503.083333</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>obtain_wooden_button</td>\n",
       "      <td>23</td>\n",
       "      <td>30</td>\n",
       "      <td>0.766667</td>\n",
       "      <td>1867.565217</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>obtain_sign</td>\n",
       "      <td>27</td>\n",
       "      <td>30</td>\n",
       "      <td>0.900000</td>\n",
       "      <td>1934.888889</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>obtain_wooden_pressure_plate</td>\n",
       "      <td>26</td>\n",
       "      <td>30</td>\n",
       "      <td>0.866667</td>\n",
       "      <td>1972.115385</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>obtain_chest</td>\n",
       "      <td>24</td>\n",
       "      <td>30</td>\n",
       "      <td>0.800000</td>\n",
       "      <td>2051.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>obtain_stick</td>\n",
       "      <td>26</td>\n",
       "      <td>30</td>\n",
       "      <td>0.866667</td>\n",
       "      <td>1662.461538</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>obtain_oak_stairs</td>\n",
       "      <td>26</td>\n",
       "      <td>30</td>\n",
       "      <td>0.866667</td>\n",
       "      <td>1962.000000</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                           task  success_count  num_evals  success_rate  \\\n",
       "0            obtain_wooden_slab             26         30      0.866667   \n",
       "1                 obtain_planks             24         30      0.800000   \n",
       "2          obtain_wooden_button             23         30      0.766667   \n",
       "3                   obtain_sign             27         30      0.900000   \n",
       "4  obtain_wooden_pressure_plate             26         30      0.866667   \n",
       "5                  obtain_chest             24         30      0.800000   \n",
       "6                  obtain_stick             26         30      0.866667   \n",
       "7             obtain_oak_stairs             26         30      0.866667   \n",
       "\n",
       "   average_episode_length  \n",
       "0             1966.769231  \n",
       "1             1503.083333  \n",
       "2             1867.565217  \n",
       "3             1934.888889  \n",
       "4             1972.115385  \n",
       "5             2051.000000  \n",
       "6             1662.461538  \n",
       "7             1962.000000  "
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import pandas as pd\n",
    "from statistics import mean\n",
    "\n",
    "results = []\n",
    "# goal_histories_data\n",
    "for task, data in task_data.items():\n",
    "    print(task)\n",
    "    print(len(data[\"episode_lengths\"]))\n",
    "    print(data)\n",
    "    results.append(\n",
    "        {\n",
    "            \"task\": task,\n",
    "            \"success_count\": data[\"success_count\"],\n",
    "            \"num_evals\": data[\"num_evals\"],\n",
    "            \"success_rate\": data[\"success_rate\"],\n",
    "            \"average_episode_length\": mean(data[\"episode_lengths\"]),\n",
    "        }\n",
    "    )\n",
    "\n",
    "df = pd.DataFrame(results)\n",
    "df"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "goal_histories_data = defaultdict(dict)\n",
    "for goal_history in goal_histories:\n",
    "    with open(goal_history, \"r\") as f:\n",
    "        name = goal_history.split(\"/\")[-2]\n",
    "        iteration = goal_history.split(\"/\")[-1].split(\"_\")[-3]\n",
    "        goal_histories_data[name][int(iteration)] = []\n",
    "        for line in f:\n",
    "            goal_histories_data[name][int(iteration)].append(json.loads(line))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "obtain_wooden_slab 20 613\n",
      "obtain_wooden_slab 21 1363\n",
      "obtain_wooden_slab 13 3000\n",
      "obtain_wooden_slab 6 1963\n",
      "obtain_wooden_slab 25 1963\n",
      "obtain_wooden_slab 14 1963\n",
      "obtain_wooden_slab 12 1963\n",
      "obtain_wooden_slab 19 1963\n",
      "obtain_wooden_slab 5 1963\n",
      "obtain_wooden_slab 18 3000\n",
      "obtain_wooden_slab 22 1963\n",
      "obtain_wooden_slab 29 1963\n",
      "obtain_wooden_slab 3 1963\n",
      "obtain_wooden_slab 4 1963\n",
      "obtain_wooden_slab 11 1963\n",
      "obtain_wooden_slab 26 1963\n",
      "obtain_wooden_slab 10 1963\n",
      "obtain_wooden_slab 2 1963\n",
      "obtain_wooden_slab 8 1963\n",
      "obtain_wooden_slab 17 1963\n",
      "obtain_wooden_slab 16 1963\n",
      "obtain_wooden_slab 15 1963\n",
      "obtain_wooden_slab 7 1963\n",
      "obtain_wooden_slab 9 1963\n",
      "obtain_wooden_slab 27 1963\n",
      "obtain_wooden_slab 0 1963\n",
      "obtain_planks 6 354\n",
      "obtain_planks 27 1963\n",
      "obtain_planks 8 1963\n",
      "obtain_planks 19 1963\n",
      "obtain_planks 10 1963\n",
      "obtain_planks 0 1963\n",
      "obtain_planks 24 1963\n",
      "obtain_planks 2 515\n",
      "obtain_planks 17 312\n",
      "obtain_planks 9 350\n",
      "obtain_planks 22 1206\n",
      "obtain_planks 21 577\n",
      "obtain_planks 16 1963\n",
      "obtain_planks 29 984\n",
      "obtain_planks 12 1148\n",
      "obtain_planks 14 533\n",
      "obtain_planks 13 1963\n",
      "obtain_planks 28 2415\n",
      "obtain_planks 18 1159\n",
      "obtain_planks 1 3000\n",
      "obtain_planks 23 1963\n",
      "obtain_planks 26 1952\n",
      "obtain_planks 20 1963\n",
      "obtain_planks 11 1963\n",
      "obtain_wooden_button 16 1963\n",
      "obtain_wooden_button 4 3000\n",
      "obtain_wooden_button 11 633\n",
      "obtain_wooden_button 3 1213\n",
      "obtain_wooden_button 29 1963\n",
      "obtain_wooden_button 12 463\n",
      "obtain_wooden_button 13 1963\n",
      "obtain_wooden_button 15 1963\n",
      "obtain_wooden_button 27 1963\n",
      "obtain_wooden_button 0 1963\n",
      "obtain_wooden_button 21 1963\n",
      "obtain_wooden_button 7 3000\n",
      "obtain_wooden_button 19 1963\n",
      "obtain_wooden_button 26 1963\n",
      "obtain_wooden_button 6 1963\n",
      "obtain_wooden_button 5 763\n",
      "obtain_wooden_button 18 1963\n",
      "obtain_wooden_button 9 997\n",
      "obtain_wooden_button 20 1963\n",
      "obtain_wooden_button 25 1963\n",
      "obtain_wooden_button 8 1963\n",
      "obtain_wooden_button 10 1963\n",
      "obtain_wooden_button 28 1963\n",
      "obtain_wooden_button 23 1963\n",
      "obtain_sign 25 1813\n",
      "obtain_sign 7 1963\n",
      "obtain_sign 16 1963\n",
      "obtain_sign 18 1963\n",
      "obtain_sign 15 1963\n",
      "obtain_sign 9 1963\n",
      "obtain_sign 20 1563\n",
      "obtain_sign 29 1963\n",
      "obtain_sign 6 1963\n",
      "obtain_sign 22 1963\n",
      "obtain_sign 24 2581\n",
      "obtain_sign 11 1963\n",
      "obtain_sign 23 1963\n",
      "obtain_sign 27 1963\n",
      "obtain_sign 13 1963\n",
      "obtain_sign 10 1963\n",
      "obtain_sign 14 1963\n",
      "obtain_sign 28 463\n",
      "obtain_sign 8 1963\n",
      "obtain_sign 4 1963\n",
      "obtain_sign 26 1963\n",
      "obtain_sign 19 1963\n",
      "obtain_sign 2 2363\n",
      "obtain_sign 1 1963\n",
      "obtain_sign 12 1963\n",
      "obtain_sign 5 1963\n",
      "obtain_sign 0 1963\n",
      "obtain_sign 3 763\n",
      "obtain_wooden_pressure_plate 15 1963\n",
      "obtain_wooden_pressure_plate 1 1963\n",
      "obtain_wooden_pressure_plate 7 1963\n",
      "obtain_wooden_pressure_plate 26 1963\n",
      "obtain_wooden_pressure_plate 27 1963\n",
      "obtain_wooden_pressure_plate 18 1963\n",
      "obtain_wooden_pressure_plate 23 1377\n",
      "obtain_wooden_pressure_plate 5 1963\n",
      "obtain_wooden_pressure_plate 3 1963\n",
      "obtain_wooden_pressure_plate 4 1963\n",
      "obtain_wooden_pressure_plate 0 1963\n",
      "obtain_wooden_pressure_plate 2 1963\n",
      "obtain_wooden_pressure_plate 8 1863\n",
      "obtain_wooden_pressure_plate 22 1963\n",
      "obtain_wooden_pressure_plate 24 1963\n",
      "obtain_wooden_pressure_plate 10 1963\n",
      "obtain_wooden_pressure_plate 20 2912\n",
      "obtain_wooden_pressure_plate 13 1963\n",
      "obtain_wooden_pressure_plate 28 1963\n",
      "obtain_wooden_pressure_plate 6 1963\n",
      "obtain_wooden_pressure_plate 25 1963\n",
      "obtain_wooden_pressure_plate 14 1963\n",
      "obtain_wooden_pressure_plate 19 1963\n",
      "obtain_wooden_pressure_plate 16 1963\n",
      "obtain_wooden_pressure_plate 9 1963\n",
      "obtain_wooden_pressure_plate 12 1963\n",
      "obtain_chest 6 1963\n",
      "obtain_chest 4 1963\n",
      "obtain_chest 3 1963\n",
      "obtain_chest 25 1963\n",
      "obtain_chest 10 1963\n",
      "obtain_chest 5 1963\n",
      "obtain_chest 16 1963\n",
      "obtain_chest 22 2153\n",
      "obtain_chest 2 1963\n",
      "obtain_chest 9 613\n",
      "obtain_chest 20 1963\n",
      "obtain_chest 13 1963\n",
      "obtain_chest 28 1963\n",
      "obtain_chest 14 1963\n",
      "obtain_chest 17 3000\n",
      "obtain_chest 23 3000\n",
      "obtain_chest 7 1963\n",
      "obtain_chest 15 1813\n",
      "obtain_chest 0 3000\n",
      "obtain_chest 29 2298\n",
      "obtain_chest 21 1963\n",
      "obtain_chest 18 1963\n",
      "obtain_chest 8 1963\n",
      "obtain_chest 27 1963\n",
      "obtain_stick 15 1963\n",
      "obtain_stick 25 1213\n",
      "obtain_stick 5 1963\n",
      "obtain_stick 0 1963\n",
      "obtain_stick 13 1963\n",
      "obtain_stick 2 617\n",
      "obtain_stick 23 1663\n",
      "obtain_stick 1 1963\n",
      "obtain_stick 10 1963\n",
      "obtain_stick 29 1963\n",
      "obtain_stick 27 1963\n",
      "obtain_stick 22 1963\n",
      "obtain_stick 7 1963\n",
      "obtain_stick 20 389\n",
      "obtain_stick 18 1963\n",
      "obtain_stick 11 1963\n",
      "obtain_stick 4 1963\n",
      "obtain_stick 26 1963\n",
      "obtain_stick 8 324\n",
      "obtain_stick 16 1963\n",
      "obtain_stick 14 1084\n",
      "obtain_stick 12 1963\n",
      "obtain_stick 21 1963\n",
      "obtain_stick 24 613\n",
      "obtain_stick 17 1963\n",
      "obtain_stick 3 2013\n",
      "obtain_fence 0 3000\n",
      "obtain_oak_stairs 8 1963\n",
      "obtain_oak_stairs 26 1963\n",
      "obtain_oak_stairs 18 1963\n",
      "obtain_oak_stairs 10 1963\n",
      "obtain_oak_stairs 13 1963\n",
      "obtain_oak_stairs 11 1963\n",
      "obtain_oak_stairs 3 1963\n",
      "obtain_oak_stairs 22 1963\n",
      "obtain_oak_stairs 16 1963\n",
      "obtain_oak_stairs 14 1963\n",
      "obtain_oak_stairs 17 1963\n",
      "obtain_oak_stairs 27 1963\n",
      "obtain_oak_stairs 20 1963\n",
      "obtain_oak_stairs 21 1963\n",
      "obtain_oak_stairs 19 1963\n",
      "obtain_oak_stairs 12 1963\n",
      "obtain_oak_stairs 28 1963\n",
      "obtain_oak_stairs 25 1963\n",
      "obtain_oak_stairs 0 1963\n",
      "obtain_oak_stairs 6 1963\n",
      "obtain_oak_stairs 1 1963\n",
      "obtain_oak_stairs 29 1963\n",
      "obtain_oak_stairs 24 1963\n",
      "obtain_oak_stairs 4 1963\n",
      "obtain_oak_stairs 2 1963\n",
      "obtain_oak_stairs 5 1963\n"
     ]
    }
   ],
   "source": [
    "for task in goal_histories_data.keys():\n",
    "    for iteration in goal_histories_data[task].keys():\n",
    "        print(task, iteration, len(goal_histories_data[task][iteration]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['obtain', 'oak', 'stairs', '5', 'goal', 'history.jsonl']"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "goal_history.split(\"/\")[-1].split(\"_\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "# read full log file: /home/gautier/Desktop/plancraft/outputs/2024-02-15/22-32-07/main.log\n",
    "main_log_file = \"/home/gautier/Desktop/plancraft/outputs/2024-02-15/22-32-07/main.log\"\n",
    "\n",
    "with open(main_log_file, \"r\") as f:\n",
    "    text = f.readlines()\n",
    "\n",
    "\n",
    "data_logs = defaultdict(list)\n",
    "logs_for_task_at_iteration = []\n",
    "task = None\n",
    "for line in text:\n",
    "    if \"Evaluating the task is \" in line:\n",
    "        if task:\n",
    "            data_logs[task].append(logs_for_task_at_iteration)\n",
    "\n",
    "        task = line.split(\"Evaluating the task is \")[1].replace(\"\\n\", \"\")     \n",
    "        logs_for_task_at_iteration = []\n",
    "\n",
    "    logs_for_task_at_iteration.append(line)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "log_results = defaultdict(dict)\n",
    "for task in data_logs.keys():\n",
    "    success_count = 0\n",
    "    finished_goals = []\n",
    "    planning_error = 0\n",
    "    parsing_error = 0\n",
    "    for iteration in range(len(data_logs[task])):\n",
    "        achieved_goals = []\n",
    "        for line in data_logs[task][iteration]:\n",
    "            if \"finish goal\" in line:\n",
    "                goal = line.split(\"finish goal \")[1].replace(\"\\n\", \"\").replace(\".\", \"\")\n",
    "                achieved_goals.append(goal)\n",
    "                if goal.replace(\"craft\", \"obtain\") == task:\n",
    "                    success_count += 1\n",
    "\n",
    "            if \"replanning over\" in line:\n",
    "                planning_error += 1\n",
    "                break\n",
    "            if \"parsed goal is not supported by current controller\" in line:\n",
    "                parsing_error += 1\n",
    "                \n",
    "        finished_goals.append(achieved_goals)\n",
    "\n",
    "    log_results[task][\"goals\"] = finished_goals\n",
    "    log_results[task][\"planning_error\"] = planning_error\n",
    "    log_results[task][\"success_count\"] = success_count\n",
    "    log_results[task][\"parsing_error\"] = parsing_error"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "# data_logs[task][iteration]\n",
    "\n",
    "df_data = []\n",
    "for task in log_results.keys():\n",
    "    df_data.append(\n",
    "        {\n",
    "            \"task\": task.replace(\"obtain_\", \"\"),\n",
    "            \"success_count\": log_results[task][\"success_count\"],\n",
    "            \"planning_error\": log_results[task][\"planning_error\"],\n",
    "            \"parsing_error\": log_results[task][\"parsing_error\"],\n",
    "            \"success_rate\": log_results[task][\"success_count\"] / len(data_logs[task]),\n",
    "        }\n",
    "    )\n",
    "\n",
    "df = pd.DataFrame(df_data)\n",
    "\n",
    "df.to_csv(\"results.csv\", index=False)\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "plancraft",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
